#pragma once

#include <string>

#include <gmpxx.h>
#include <armadillo>
#include <vector>
#include <istream>
#include <ostream>

namespace skyfire
{
    constexpr int SF_RC_PASSWORD_BIT_COUNT = 10000;
    constexpr int SF_RC_PASSWORD_INIT_TIMES = 10000;
    

    using sf_byte = unsigned char;
    using sf_float = mpf_class;
    using sf_byte_array = std::vector<sf_byte >;

    inline sf_byte_array& operator += (sf_byte_array &data1, const sf_byte_array& data2)
    {
        data1.insert(data1.end(), data2.begin(), data2.end());
        return data1;
    }

    inline sf_byte_array str2bytearray(const std::string& str)
    {
        return sf_byte_array{str.begin(), str.end()};
    }

    inline std::string bytearray2str(const sf_byte_array& data)
    {
        return std::string{data.begin(), data.end()};
    }


    class sf_rc
    {
        public:
        sf_rc(const std::string& ps);

        sf_byte_array enc(const sf_byte_array& data);

        sf_byte_array dec(const sf_byte_array& data);

        bool enc(std::istream *in, std::ostream *out);

        bool dec(std::istream *in, std::ostream *out);

        private:
        mpf_class password__;

        mpf_class u__ ;

        void init_u__();

        std::vector<sf_float> make_logistic_col__(int len);

        arma::Col<sf_byte> map_to_n_byte__(const std::vector<sf_float> &data,sf_byte n);

        arma::Col<int> map_to_n_int__(const std::vector<sf_float> &data,int n);

        arma::Mat<sf_byte> make_chaos_mat__();

        arma::Col<sf_byte > make_random_list__(int len);

        sf_byte_array enc_block__(const sf_byte_array& data);

        sf_byte_array dec_block__(const sf_byte_array& data);
    };
}